package com.wzh.multithreaddemo;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.util.MutableInt;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.wzh.advancelog.log.WzhLog;
import com.wzh.multithreaddemo.databinding.ActivityMainBinding;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.schedulers.Schedulers;

@SuppressLint("DefaultLocale")
public class MainActivity extends AppCompatActivity {
    ActivityMainBinding mBinding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        mBinding.btnNewToMain.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                newToMain();
            }
        });
        mBinding.btnMainToNew.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mainToNew();
            }
        });
        mBinding.btnCacheThreadPoll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                cacheThreadPool();
            }
        });
        mBinding.btnFixedThreadPoll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                fixedThreadPool();
            }
        });
        mBinding.btnSingleThreadPool.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                singleThreadPool();
            }
        });
        mBinding.btnScheduledThreadPool.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scheduledThreadPool();
            }
        });
        mBinding.btnThreadName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                customThreadName();
            }
        });
        mBinding.btnFuture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                future();
            }
        });
        mBinding.btnIntentService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intentService();
            }
        });
        mBinding.btnAsyncTask.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                asyncTask();
            }
        });

        mBinding.btnRxjava.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                rxjava();
            }
        });
    }

    MutableLiveData<Integer> progressLiveData = new MutableLiveData<>();
    CompositeDisposable compositeDisposable = new CompositeDisposable();

    private void rxjava() {
        progressLiveData.observe(this, new androidx.lifecycle.Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,progress update:%s", Thread.currentThread().getName(), integer));
            }
        });
        Observable.create(
                new ObservableOnSubscribe<String>() {
                    @Override
                    public void subscribe(@io.reactivex.rxjava3.annotations.NonNull ObservableEmitter<String> emitter) throws Throwable {
                        WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,任务开始,参数:%s", Thread.currentThread().getName(), "1"));
                        emitter.onNext("1");
                    }
                })
                .subscribeOn(AndroidSchedulers.mainThread())
                .observeOn(Schedulers.io())
                .map(new Function<String, String>() {
                    @Override
                    public String apply(String s) throws Throwable {
                        for (int i = 0; i < 5; i++) {
                            progressLiveData.postValue(i * 20);
                            WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,progress:%s", Thread.currentThread().getName(), i * 20));
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,参数:%s,执行完毕", Thread.currentThread().getName(), s));
                        return "success";
                    }
                })
                .observeOn(AndroidSchedulers.mainThread()).subscribe(
                new Observer<String>() {
                    @Override
                    public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
                        compositeDisposable.add(d);
                    }

                    @Override
                    public void onNext(@io.reactivex.rxjava3.annotations.NonNull String s) {
                        WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,已完成,结果是:%s", Thread.currentThread().getName(), s));
                    }

                    @Override
                    public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                        compositeDisposable.dispose();
                    }
                });
    }

    /*
        AsyncTask缺点:任务容易取消不掉,造成内存泄漏
     */
    static class MyAsyncTask extends AsyncTask<String, Integer, String> {
        @Override
        protected void onPreExecute() {
            WzhLog.i(LogTag.WZH_LOG, Thread.currentThread().getName());
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String... strings) {
            for (int i = 0; i < 5; i++) {
                publishProgress(i * 20);
                WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,progress:%s", Thread.currentThread().getName(), i * 20));
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,参数:%s,执行完毕", Thread.currentThread().getName(), strings[0]));
            return "success";
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,progress update:%s", Thread.currentThread().getName(), values[0]));
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            WzhLog.i(LogTag.WZH_LOG, String.format("线程:%s,已完成,结果是:%s", Thread.currentThread().getName(), s));
        }
    }

    @SuppressLint("StaticFieldLeak")
    private void asyncTask() {
        AsyncTask<String, Integer, String> task =
                new MyAsyncTask();
        task.execute("1");
    }

    private void intentService() {
        for (int i = 1; i < 11; i++) {
            Intent intent = new Intent(MainActivity.this, MyIntentService.class);
            intent.putExtra(IntentTag.INDEX, i);
            startService(intent);
        }
    }

    private void future() {
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
        Future<String> future = singleThreadPool.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "success";
            }
        });
        try {
            String str = future.get();
            WzhLog.i(LogTag.WZH_LOG, "future.get()" + str);
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程执行异常的捕获
        Future<String> exceptionFuture = singleThreadPool.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                int a = 1 / 0;
                return "";
            }
        });
        try {
            exceptionFuture.get();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(LogTag.WZH_LOG, "exceptionFuture", e);
        }
    }


    int index;
    int threadNameIndex;

    private void customThreadName() {
        threadNameIndex = 0;
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3, new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                threadNameIndex++;
                thread.setName("测试线程wzh" + threadNameIndex);
                thread.setPriority(Thread.MAX_PRIORITY);
                return thread;
            }
        });
        index = 0;
        for (int i = 0; i < 10; i++) {
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    index++;
                    WzhLog.i(LogTag.WZH_LOG, String.format("执行第%d次(%s)", index, Thread.currentThread().getName()));
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private void scheduledThreadPool() {
        index = 0;
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                index++;
                WzhLog.i(LogTag.WZH_LOG, String.format("执行第%d次(%s)", index, Thread.currentThread().getName()));
                if (index >= 10) {
                    scheduledThreadPool.shutdown();
                }
            }
        }, 0, 1000, TimeUnit.MILLISECONDS);

    }

    private void singleThreadPool() {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        index = 0;
        for (int i = 0; i < 10; i++) {
            singleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    index++;
                    WzhLog.i(LogTag.WZH_LOG, String.format("执行第%d次(%s)", index, Thread.currentThread().getName()));
                }
            });
        }
    }

    private void fixedThreadPool() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        index = 0;
        for (int i = 0; i < 10; i++) {
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    index++;
                    WzhLog.i(LogTag.WZH_LOG, String.format("执行第%d次(%s)", index, Thread.currentThread().getName()));
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private void cacheThreadPool() {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        index = 0;
        for (int i = 0; i < 10; i++) {
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    index++;
                    WzhLog.i(LogTag.WZH_LOG, String.format("执行第%d次(%s)", index, Thread.currentThread().getName()));
                }
            });
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 10; i++) {
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    index++;
                    WzhLog.i(LogTag.WZH_LOG, String.format("执行第%d次(%s)", index, Thread.currentThread().getName()));
                }
            });
        }
    }

    @SuppressLint("HandlerLeak")
    private final Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            WzhLog.i(LogTag.WZH_LOG, Thread.currentThread().getName());
        }
    };

    private void newToMain() {
        WzhLog.i(LogTag.WZH_LOG, Thread.currentThread().getName());
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    WzhLog.i(LogTag.WZH_LOG, Thread.currentThread().getName());
                    Thread.sleep(1000);
                    handler.sendEmptyMessage(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    static class MyThread extends Thread {
        public Handler handler;

        @Override
        public void run() {
            Looper.prepare();
            handler = new Handler(Looper.myLooper()) {
                @Override
                public void handleMessage(@NonNull Message msg) {
                    WzhLog.i(LogTag.WZH_LOG, Thread.currentThread().getName());
                    Looper.myLooper().quit();
                }
            };
            Looper.loop();
        }
    }

    private void mainToNew() {
        MyThread thread = new MyThread();
        thread.start();
        WzhLog.i(LogTag.WZH_LOG, Thread.currentThread().getName());
        thread.handler.sendEmptyMessageDelayed(0, 500);
        thread.handler.sendEmptyMessageDelayed(0, 1000);
    }


}